package com.lechi.web.service.impl;

import com.lechi.web.common.config.LeChiConfig;
import com.lechi.web.common.constant.ScheduleConstants;
import com.lechi.web.common.enums.ErrorCodeEnum;
import com.lechi.web.common.exception.ServiceException;
import com.lechi.web.common.exception.job.TaskException;
import com.lechi.web.framework.log.IotExceptionLog;
import com.lechi.web.service.IIotScheduleJobService;
import com.lechi.web.system.domain.IotScheduleJobBo;
import com.lechi.web.system.mapper.iot.IotScheduleJobMapper;
import com.lechi.web.util.ScheduleUtils;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 定时任务调度信息 服务层
 *
 * @author yg
 */
@Slf4j
@Service
public class IotScheduleJobServiceImpl implements IIotScheduleJobService {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private IotScheduleJobMapper iotScheduleJobMapper;

    @Autowired
    private LeChiConfig leChiConfig;

    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @PostConstruct
    public void init() {
        if ("DaPeng".equals(leChiConfig.getName())) {
            return;
        }
        try {
//            if (Epoll.isAvailable()) {
                log.error("设备周期数据检查&发送指令调度任务：scheduler.clear();");
                scheduler.clear();
                List<IotScheduleJobBo> jobList = iotScheduleJobMapper.selectJobAll();
                for (IotScheduleJobBo job : jobList) {
                    if ("true".equals(job.getStatus())) {
                        log.error("设备周期数据检查&发送指令调度任务：{}", job);
                        ScheduleUtils.createScheduleJob(scheduler, job, "DefaultJob");
                    }
                }
//            }
        } catch (Exception e) {
            log.error("设备周期数据检查&发送指令调度任务", e);
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "初始化任务调度", method, ""));
        }
    }

    /**
     * 获取quartz调度器的计划任务列表
     *
     * @param job 调度信息
     */
    @Override
    public List<IotScheduleJobBo> selectJobList(IotScheduleJobBo job) {
        return iotScheduleJobMapper.selectJobList(job);
    }

    /**
     * 通过调度任务ID查询调度信息
     *
     * @param jobId 调度任务ID
     * @return 调度任务对象信息
     */
    @Override
    public IotScheduleJobBo selectJobById(Long jobId) {
        return iotScheduleJobMapper.selectJobById(jobId);
    }

    /**
     * 暂停任务
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int pauseJob(IotScheduleJobBo job){
        int rows = 0;
        try {
            Long jobId = job.getId();
            job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
            rows = iotScheduleJobMapper.updateJob(job);
            if (rows > 0) {
                scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, "DefaultJob"));
            }
        } catch (SchedulerException e) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "终止任务调度", method, job));
            throw new ServiceException(ErrorCodeEnum.UPDATE_ERROR.getValue(), ErrorCodeEnum.UPDATE_ERROR.getKey());
        }
        return rows;
    }

    /**
     * 恢复任务
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int resumeJob(IotScheduleJobBo job) throws SchedulerException {
        Long jobId = job.getId();
        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        int rows = iotScheduleJobMapper.updateJob(job);
        if (rows > 0) {
            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, "DefaultJob"));
        }
        return rows;
    }

    /**
     * 批量删除调度信息
     *
     * @param jobIds 需要删除的任务ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteJobByIds(Long[] jobIds) {
        try {
            for (Long jobId : jobIds) {
                int rows = iotScheduleJobMapper.deleteJobById(jobId);
                if (rows > 0) {
                    scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, "DefaultJob"));
                }
            }
        } catch (Exception e) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "删除任务调度", method, jobIds));
            throw new ServiceException(ErrorCodeEnum.UPDATE_ERROR.getValue(), ErrorCodeEnum.UPDATE_ERROR.getKey());
        }
    }

    /**
     * 任务调度状态修改
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int changeStatus(IotScheduleJobBo job) {
        int rows = 0;
        try {
        String status = job.getStatus();
            if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) {
                rows = resumeJob(job);
            } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) {
                rows = pauseJob(job);
            }
        } catch (Exception e) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "任务调度状态修改", method, job));
            throw new ServiceException(ErrorCodeEnum.UPDATE_ERROR.getValue(), ErrorCodeEnum.UPDATE_ERROR.getKey());
        }
        return rows;
    }

    /**
     * 立即运行任务
     *
     * @param job 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean run(IotScheduleJobBo job) {
        boolean result = false;
        try {
            Long jobId = job.getId();
            IotScheduleJobBo properties = selectJobById(job.getId());
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
            JobKey jobKey = ScheduleUtils.getJobKey(jobId, "DefaultJob");
            if (scheduler.checkExists(jobKey)) {
                result = true;
                scheduler.triggerJob(jobKey, dataMap);
            }
        } catch (Exception e) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "立即执行任务", method, job));
            throw new ServiceException(ErrorCodeEnum.UPDATE_ERROR.getValue(), ErrorCodeEnum.UPDATE_ERROR.getKey());
        }
        return result;
    }

    /**
     * 新增任务
     *
     * @param job 调度信息 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertJob(IotScheduleJobBo job) {
        IotScheduleJobBo properties = selectJobById(job.getId());
        int rows = 0;
        try {
            if (properties != null) {
                rows = iotScheduleJobMapper.updateJob(job);
                if (rows > 0) {
                    updateSchedulerJob(job, "DefaultJob");
                }
            } else {
                rows = iotScheduleJobMapper.insertJob(job);
                if (rows > 0 && "true".equals(job.getStatus())) {
                    ScheduleUtils.createScheduleJob(scheduler, job, "DefaultJob");
                }
            }
        } catch (Exception e) {
            StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
            String method = Thread.currentThread().getName() + ":" + stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName();
            CompletableFuture.runAsync(IotExceptionLog.exceptionLog(e, "新增或者修改调度任务", method, job));
            throw new ServiceException(ErrorCodeEnum.ADD_ERROR.getValue(), ErrorCodeEnum.ADD_ERROR.getKey());
        }
        return rows;
    }


    /**
     * 更新任务
     *
     * @param job      任务对象
     * @param jobGroup 任务组名
     */
    public void updateSchedulerJob(IotScheduleJobBo job, String jobGroup) throws SchedulerException, TaskException {
        Long jobId = job.getId();
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey) || "false".equals(job.getStatus())) {
            scheduler.deleteJob(jobKey);
        }
        if (!scheduler.checkExists(jobKey) && "true".equals(job.getStatus())) {
            ScheduleUtils.createScheduleJob(scheduler, job, "DefaultJob");
        }
    }
}
